#region license
# This file is part of Grawlix.
# 
# Grawlix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# 
# Grawlix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with Grawlix.  If not, see
# <http://www.gnu.org/licenses/>.
#endregion

"""
Engine hub, locating global services.
Remarks: Inversion of Control container based upon the Castle WindsorContainer.
"""

namespace Grawlix.Services
import Grawlix.Services.Resources
import ConcurrentBoo
import System

final transient class Game(ServiceProvider):
"""Access to global service objects ."""
	
	def constructor([required] config as ServiceConfiguration):
	"""
	Initializes the Game with specified service configuration.
	Param config: The configuration information for this provider.
	"""
		super(config)
		_computation = Primitive.Asynchronously() do:
			_domainProvider = self.FindService[of IDomainProvider]()
			_main = FindDomain(_mainName)
	
	def constructor(
		[required] config as ServiceConfiguration,
		[required] parent as ServiceProvider):
	"""
	Initializes the Game with specified service configuration.
	Param config: The configuration information for this provider.
	Param parent: The parent service provider.
	"""
		super(config, parent)
		_computation = Primitive.Asynchronously() do:
			_domainProvider = self.FindService[of IDomainProvider]()
			_main = FindDomain(_mainName)
	
	def FindDomain([required] name as string):
	"""
	Look up a domain by name, loading if needed.
	Param name: The name of the domain to access.
	Returns: The domain, which may not yet be loaded.
	"""
		# Compiler bug; need to put in self explicitly
		return _domainProvider.Find(name, self)
	
	def FindResource[of
		T/*(interface, IDynamicResource)*/](
		[required] uri as Uri):
	"""
	Finds a specified type of resource.
	Param uri: The URI of the resource path.
	Returns: The resource found.
	Raises ServiceNotFoundException:
		If the correct type of resource factory could not be found.
	"""
		factory as IResourceFactory[of T] = \
			FindService(typeof(IResourceFactory[of T]))
		return factory.Find(uri)
	
	def ReloadResource[of
		T/*(inteface, IDynamicResource)*/](
		[required] resource as T):
	"""
	Reloads a resource from disk.
	Param resource: The resource to reload.
	Raises ServiceLoadException:
		If the correct type of resource factory could not be found.
	"""
		# Compiler bug; need to put in self explicitly
		self.FindService[of IResourceFactory[of T]]().Reload(resource)
	
	override def ToString():
	"""
	Get a string representation for this object.
	Returns: A string representation for this object.
	"""
		return "Game ${FriendlyName}"
	
	Ready:
	"""Whether the game has finished loading."""
		get:
			return (_main is not null and _main.Ready) or \
				(_computation.Finished and _computation.Failure is not null)
	
	Failure:
	"""
	The exception that caused the game to fail to load,
	or nothing on success.
	"""
		get:
			if not Ready:
				raise InvalidOperationException(
					"Attempt to check on the failure result of " + 
					"a game object (${self}) " +
					"when it is not finished loading. " +
					"First check the Ready property to see " +
					"if the load is finished.")
			if _computation.Failure is not null:
				return _computation.Failure
			return _main.Failure
	
	Main:
	"""The main controlling game domain."""
		get:
			if _main is null:
				if _domainProvider is not null:
				# Allow main domain to access the Main property
					return _domainProvider.Find(_mainName, self)
				raise InvalidOperationException(
					"Attempt to access the main domain when it " +
					"has not fully loaded. " +
					"Be sure that the Ready property is true and " +
					"the Failure property is null before " +
					"accessing the main domain.")
			return _main
	
	Domains:
	"""A set of the active map domains."""
		get:
			if _domainProvider is null:
				raise InvalidOperationException(
					"Attempt to access the domain list when it " +
					"has not fully loaded. " +
					"Be sure that the Ready property is true and " +
					"the Failure property is null before " +
					"accessing the domain list.")
			return _domainProvider.Domains
	
	private _computation as Computation
	"""The overlapped computation object to use while loading."""
	
	private _domainProvider as IDomainProvider
	"""The directory leading to all domains."""
	
	private _main as Domain
	"""The main game domain."""
	
	private _mainName = "main"
	"""The name of the main domain."""
	
